package com.gl.portal.system.service;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

import javax.annotation.PostConstruct;
import javax.persistence.criteria.Predicate;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cglib.beans.BeanCopier;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.stereotype.Service;

import com.gl.common.constant.Constants;
import com.gl.common.constant.RedisConstants;
import com.gl.common.exception.CustomException;
import com.gl.common.util.SecurityUtils;
import com.gl.common.util.StringUtils;
import com.gl.common.util.redis.RedisUtils;
import com.gl.framework.security.LoginUser;
import com.gl.framework.web.domain.PageData;
import com.gl.portal.system.entity.SysConfig;
import com.gl.portal.system.repository.SysConfigRepository;
import com.gl.portal.system.vo.SysConfigVo;
import com.gl.portal.system.vo.SysUserVo;

/**
 * 参数配置服务实现类
 */
@Service
public class SysConfigService {

    @Autowired
    private SysConfigRepository configRepository;

    @Autowired
    private RedisUtils redisUtils;

    /**
     * 项目启动时，初始化参数到缓存
     */
    @PostConstruct
    public void init() {
        List<SysConfig> configsList = configRepository.findAll();
        Map<String, Object> dataMap = configsList.stream().collect(Collectors.toMap(SysConfig::getKey, SysConfig::getValue));
        if (StringUtils.isNotEmpty(dataMap)) {
            redisUtils.hmset(RedisConstants.MZJ_MG_PARAMS, dataMap);
        } else {
            redisUtils.del(RedisConstants.MZJ_MG_PARAMS);
        }
    }

    /**
     * 查询参数配置信息
     *
     * @param configId 参数配置ID
     * @return 参数配置信息
     */
    public SysConfigVo selectConfigById(Long configId) {
        Optional<SysConfig> optional = configRepository.findById(configId);
        if (!optional.isPresent()) {
            throw new CustomException("数据不存在");
        }

        SysConfig sysConfig = optional.get();

        BeanCopier beanCopier = BeanCopier.create(SysConfig.class, SysConfigVo.class, false);
        SysConfigVo vo = new SysConfigVo();
        beanCopier.copy(sysConfig, vo, null);

        return vo;
    }

    /**
     * 根据键名查询参数配置信息
     *
     * @param key 参数key
     * @return 参数键值
     */
    public String selectConfigByKey(String key) {
        Object value = redisUtils.hget(RedisConstants.MZJ_MG_PARAMS, key);
        if (value != null) {
            return value.toString();
        }

        SysConfig retConfig = configRepository.findByKey(key);
        if (StringUtils.isNotNull(retConfig)) {
            redisUtils.hset(RedisConstants.MZJ_MG_PARAMS, retConfig.getKey(), retConfig.getValue());
            return retConfig.getValue();
        }
        return StringUtils.EMPTY;
    }

    /**
     * 查询参数配置列表
     *
     * @param filter 过滤条件
     * @return
     */
    public PageData<SysConfigVo> selectConfigList(SysConfigVo filter) {
        PageData<SysConfigVo> pageData = new PageData<>();

        Page<SysConfigVo> page = configRepository.findAll((root, query, criteriaBuilder) -> {
            Predicate predicate = criteriaBuilder.and();

            if (StringUtils.isNotBlank(filter.getName())) {
                predicate = criteriaBuilder.and(predicate, criteriaBuilder.like(root.get("name"), "%" + filter.getName() + "%"));
            }
            if (StringUtils.isNotBlank(filter.getKey())) {
                predicate = criteriaBuilder.and(predicate, criteriaBuilder.like(root.get("key"), "%" + filter.getKey() + "%"));
            }
            if (StringUtils.isNotBlank(filter.getBeginTime())) {
                predicate = criteriaBuilder.and(predicate, criteriaBuilder.greaterThan(root.get("createTime").as(String.class), filter.getBeginTime() + " 00:00:00"));
            }
            if (StringUtils.isNotBlank(filter.getEndTime())) {
                predicate = criteriaBuilder.and(predicate, criteriaBuilder.lessThan(root.get("createTime").as(String.class), filter.getEndTime() + " 23:59:59"));
            }

            predicate = criteriaBuilder.and(predicate, criteriaBuilder.equal(root.get("isDeleted").as(Integer.class), 0));

            return predicate;
        }, PageRequest.of(filter.getPageNumber() - 1, filter.getPageSize(), Direction.ASC, "id")).map(this::convert);

        long total = page.getTotalElements();
        List<SysConfigVo> data = page.getContent();

        pageData.setTotal(total);
        pageData.setData(data);

        return pageData;
    }

    /**
     * 数据转换
     *
     * @param entity
     * @return
     */
    private SysConfigVo convert(SysConfig entity) {
        BeanCopier beanCopier = BeanCopier.create(SysConfig.class, SysConfigVo.class, false);
        SysConfigVo vo = new SysConfigVo();
        beanCopier.copy(entity, vo, null);
        return vo;
    }

    /**
     * 新增参数配置
     *
     * @param vo 参数配置信息
     */
    public void saveConfig(SysConfigVo vo) {
        BeanCopier beanCopier = BeanCopier.create(SysConfigVo.class, SysConfig.class, false);
        SysConfig entity = new SysConfig();
        beanCopier.copy(vo, entity, null);

        LoginUser loginUser = SecurityUtils.getLoginUser();
        SysUserVo user = loginUser.getUser();
        entity.setCreateUserId(user.getId());
        entity.setCreateTime(new Date());
        if (entity.getIsDeleted() == null) {
            entity.setIsDeleted(0);
        }
        entity = configRepository.save(entity);

        // 同步redis
        redisUtils.hset(RedisConstants.MZJ_MG_PARAMS, entity.getKey(), entity.getValue());
    }

    /**
     * 修改参数配置
     *
     * @param vo 参数配置信息
     */
    public void updateConfig(SysConfigVo vo) {
        Optional<SysConfig> optional = configRepository.findById(vo.getId());
        if (!optional.isPresent()) {
            throw new CustomException("数据不存在");
        }
        SysConfig entity = optional.get();

        BeanCopier beanCopier = BeanCopier.create(SysConfigVo.class, SysConfig.class, false);
        beanCopier.copy(vo, entity, null);

        LoginUser loginUser = SecurityUtils.getLoginUser();
        SysUserVo user = loginUser.getUser();
        entity.setUpdateUserId(user.getId());
        entity.setUpdateTime(new Date());
        entity = configRepository.save(entity);

        // 同步redis
        redisUtils.hset(RedisConstants.MZJ_MG_PARAMS, entity.getKey(), entity.getValue());
    }

    /**
     * 批量删除参数信息
     *
     * @param configIds 需要删除的参数ID
     */
    public void deleteConfigByIds(List<Long> configIds) {
        List<SysConfig> configs = configRepository.findByIdIn(configIds);

        if (configIds.isEmpty()) {
            throw new CustomException("数据不存在");
        }

        // 删除redis缓存
        List<String> keys = configs.stream().map(config -> config.getKey()).collect(Collectors.toList());
        redisUtils.hdel(RedisConstants.MZJ_MG_PARAMS, keys.toArray());

        configRepository.deleteAll(configs);
    }

    /**
     * 清空缓存数据
     */
    public void clearCache() {
        redisUtils.del(RedisConstants.MZJ_MG_PARAMS);
    }

    /**
     * 同步缓存数据到Redis
     */
    public void copyCache() {
        List<SysConfig> configsList = configRepository.findAll();
        clearCache();
        for (SysConfig entity : configsList) {
            redisUtils.hset(RedisConstants.MZJ_MG_PARAMS, entity.getKey(), entity.getValue());
        }
    }

    /**
     * 校验参数键名是否唯一
     *
     * @param vo 参数配置信息
     * @return 结果
     */
    public String checkConfigKeyUnique(SysConfigVo vo) {
        Long configId = StringUtils.isNull(vo.getId()) ? -1L : vo.getId();
        SysConfig info = configRepository.findByKey(vo.getKey());
        if (StringUtils.isNotNull(info) && info.getId().longValue() != configId.longValue()) {
            return Constants.NOT_UNIQUE;
        }
        return Constants.UNIQUE;
    }

}
